#include <GL/glut.h>
#include <stdlib.h>

#define MUNDO 5.0f
/* Variables globales que guardan el tope de las coordenadas de mundo */
float xMax, yMax;
/* Variable global que controla la proyeccion, 0 - ortogonal, 1 perspectiva */
int projection;
/* Variable global para guardar el aspect */
double aspect;

void inicializar (void);
void redimensiona (int alto, int ancho);
void dibuja (void);
void teclado (unsigned char key, int cx, int cy);
void tecladoEspecial (int key, int cy, int cx);
void animacion (void);
void raton (int boton, int estado, int cx, int cy);
void setProjection(void);
int main(int argc, char** argv) {
   
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize (640, 480);
   glutInitWindowPosition (100, 105);
   glutCreateWindow (argv[0]);
   inicializar();
   
   glutDisplayFunc(dibuja);
   glutReshapeFunc(redimensiona);
   glutKeyboardFunc(teclado);
   glutSpecialFunc(tecladoEspecial);
   glutMouseFunc(raton);
   glutIdleFunc(animacion);
   glutMainLoop();
   
   return 0;
}

void inicializar () {
   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
   glEnable(GL_DEPTH_TEST);
   projection = 0;

   /* Iluminacion muy basica */
   glShadeModel(GL_FLAT);
   glEnable(GL_COLOR_MATERIAL);
   glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
}

void redimensiona (int ancho, int alto) {
   
   glViewport (0, 0, ancho, alto);
   
   if (alto == 0){
   	  alto = 1;
   }
   
   aspect = (double) ancho / (double) alto;
   
}

void teclado (unsigned char key, int cx, int cy) {
	
	switch (key) {
		case 27:
		   exit(0);
		break;
		
		case 'P':
		case 'p':
			projection = !projection;
		break;

		default: break;
	}
	
	glutPostRedisplay();
}

void tecladoEspecial (int key, int cy, int cx) {
	
	switch (key) {
		case GLUT_KEY_UP:
		break;
		
		case GLUT_KEY_DOWN:
		break;
		
		case GLUT_KEY_LEFT:
		break;
		
		case GLUT_KEY_RIGHT:
		break;
		
		case GLUT_KEY_HOME:
		break;
		
		case GLUT_KEY_END:
		break;

		case GLUT_KEY_F1:
		break;

		case GLUT_KEY_F12:
		break;

		case GLUT_KEY_PAGE_UP:
		break;

		case GLUT_KEY_PAGE_DOWN:
		break;

		default: break;
	}
	
	glutPostRedisplay();
}

void raton (int boton, int estado, int cx, int cy) {
	float x, y;
	
	/* Calculamos las coordenadas de mundo (relativas) apartir de 
	 * las de ventana (absolutas) */
	
	x = ((GLfloat)cx * 2.0 * xMax) / glutGet(GLUT_WINDOW_WIDTH) - xMax;
	y = yMax - ((GLfloat)cy * 2.0 * yMax) / glutGet(GLUT_WINDOW_HEIGHT);
	
	if (boton == GLUT_LEFT_BUTTON && estado == GLUT_DOWN) {
	}
	
	glutPostRedisplay();
}

void animacion (void) {
	glutPostRedisplay();
}	

void dibuja (void) {
	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	/* Transformacion de proyeccion */
	setProjection();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	/* Si la proyeccion es en perspectiva, nos movemos un poco atras,
	 * para quedar dentro del volumen de vision (que solo puede ser positivo) */
	if (projection) {
		glTranslatef(0.0, 0.0, -2.0 * MUNDO);
	}
	
	/*Transformación de Vision */
	gluLookAt(0.0, 0.0, MUNDO, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	/* Dibujar aqui!! */
	glColor3f(1.0, 1.0, 0.0);
	glRotatef(20.0, 1.0, 0.0, 0.0);
	glRotatef(30.0, 0.0, 1.0, 0.0);
	glutSolidTeapot(4.0);

	/* Usamos dos buffers por si hay animacion */
	glutSwapBuffers();
}

void setProjection () {
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();

	if (projection) { /* Vamos a poner una proyeccion en perspectiva */

		gluPerspective(38.0, aspect, MUNDO, 4.0 * MUNDO);

	} else { /* Vamos a poner una proyeccion ortogonal */

		if (aspect <= 1.0) { /* La ventana es mas alta que ancha */
			xMax = MUNDO;
			yMax = MUNDO / aspect;
		} else { /* La ventana es mas ancha que alta */
			xMax = MUNDO * aspect;
			yMax = MUNDO;
		}

		glOrtho(-xMax, xMax, -yMax, yMax, -2.0 * MUNDO, 2.0 * MUNDO);
	}
}
